package com.xl.utils.zip;

import cn.hutool.core.io.FileUtil;
import cn.hutool.core.util.ArrayUtil;
import cn.hutool.core.util.StrUtil;

import com.xl.utils.rate.SpeedLimiter;
import lombok.extern.slf4j.Slf4j;
import net.lingala.zip4j.ZipFile;
import net.lingala.zip4j.model.ZipParameters;
import net.lingala.zip4j.model.enums.AesKeyStrength;
import net.lingala.zip4j.model.enums.EncryptionMethod;
import org.apache.commons.io.IOUtils;
import org.springframework.util.FileCopyUtils;

import javax.servlet.http.HttpServletResponse;
import java.io.BufferedInputStream;
import java.io.File;
import java.io.IOException;
import java.io.OutputStream;
import java.util.ArrayList;
import java.util.List;
import java.util.Objects;

/**
 * @Author:XueH
 * @Description:
 * @Date:Created in 14:28 2023/8/9
 * @Modified By:
 */
@Slf4j
public class ZipUtil {


    public static void createZipToOutputStream(List<String> files, String outputFile
            , String pwd, HttpServletResponse response, boolean isDelete) {
        File file = createZip(files, outputFile, pwd);
        if (Objects.isNull(file)) {
            return;
        }
        try {
            BufferedInputStream inputStream = FileUtil.getInputStream(file);
            response.setContentType("application/zip");
            //可以在请求头里面吧文件名传递过去
            response.setHeader("Location", file.getName());
            response.setHeader("Content-Disposition", "attachment;filename=" + file.getName());
            FileCopyUtils.copy(inputStream, response.getOutputStream());
        } catch (IOException e) {
            log.error("压缩文件写入到输出流失败:{}", outputFile);
        } finally {
            if (isDelete && file.exists()) {
                file.delete();
            }
        }
    }


    /**
     * 压缩下载且带宽限速
     *
     * @param files
     * @param outputFile
     * @param pwd
     * @param response
     * @param isDelete
     * @param maxRate
     */
    public static void createZipWriteResponseLimitRate(List<String> files, String outputFile
            , String pwd, HttpServletResponse response, boolean isDelete, int maxRate) {
        File file = createZip(files, outputFile, pwd);
        if (Objects.isNull(file)) {
            return;
        }
        BufferedInputStream inputStream = null;
        OutputStream outputStream = null;
        try {
            inputStream = FileUtil.getInputStream(file);
            response.setContentType("application/zip");
            response.setHeader("Location", file.getName());
            response.setHeader("Content-Disposition", "attachment;filename=" + file.getName());
            outputStream = response.getOutputStream();
            byte[] buffer = new byte[1024];
            int length;
            SpeedLimiter speedLimiter = new SpeedLimiter(maxRate);
            while ((length = inputStream.read(buffer)) != -1) {
                outputStream.write(buffer, 0, length);
                speedLimiter.delayNextBytes(length);
            }
        } catch (IOException e) {
            log.error("压缩文件写入到输出流失败:{}", outputFile);
        } finally {
            IOUtils.closeQuietly(inputStream);
            IOUtils.closeQuietly(outputStream);
            if (isDelete && file.exists()) {
                file.delete();
            }
        }
    }

    public static void createZipToOutputStream(String inputDir, String outputFile
            , String pwd, HttpServletResponse response, boolean isDelete) {
        File file = createZip(inputDir, outputFile, pwd);
        if (Objects.isNull(file)) {
            return;
        }
        try {
            BufferedInputStream inputStream = FileUtil.getInputStream(file);
            response.setContentType("application/zip");
            response.setHeader("Location", file.getName());
            response.setHeader("Content-Disposition", "attachment;filename=" + file.getName());
            FileCopyUtils.copy(inputStream, response.getOutputStream());
        } catch (IOException e) {
            log.error("压缩文件写入到输出流失败:{}", outputFile);
        } finally {
            if (isDelete && file.exists()) {
                file.delete();
            }
        }
    }


    /**
     * @param files      需要压缩的文件
     * @param outputFile 文件路径+文件名称
     * @return
     */
    public static File createZip(List<String> files, String outputFile, String pwd) {
        try {
            ZipFile zipFile;
            ZipParameters zipParameters = new ZipParameters();
            if (StrUtil.isNotBlank(pwd)) {
                zipParameters.setEncryptFiles(true);
                zipParameters.setEncryptionMethod(EncryptionMethod.AES);
                zipParameters.setAesKeyStrength(AesKeyStrength.KEY_STRENGTH_256);
                zipFile = new ZipFile(outputFile, pwd.toCharArray());
            } else {
                zipFile = new ZipFile(outputFile);
            }
            List<File> filesToAdd = new ArrayList<>();
            for (String file : files) {
                filesToAdd.add(new File(file));
            }
            zipFile.addFiles(filesToAdd, zipParameters);
            return zipFile.getFile();
        } catch (Exception e) {
            e.printStackTrace();
        }
        return null;
    }

    /**
     * 单个文件压缩
     * @param sourceFile
     * @param outputFile
     * @param pwd
     * @return
     */
    public static File singleFileCreateZip(String sourceFile, String outputFile, String pwd) {
        try {
            ZipFile zipFile;
            ZipParameters zipParameters = new ZipParameters();
            if (StrUtil.isNotBlank(pwd)) {
                zipParameters.setEncryptFiles(true);
                zipParameters.setEncryptionMethod(EncryptionMethod.AES);
                zipParameters.setAesKeyStrength(AesKeyStrength.KEY_STRENGTH_256);
                zipFile = new ZipFile(outputFile, pwd.toCharArray());
            } else {
                zipFile = new ZipFile(outputFile);
            }
            zipFile.addFile(sourceFile , zipParameters);
            return zipFile.getFile();
        } catch (Exception e) {
            e.printStackTrace();
        }
        return null;
    }


    /**
     * 压缩文件夹
     *
     * @param inputDir   D:\\test  要打包的文件夹
     * @param outputFile D:\test1.zip 生成的压缩包的名字
     * @param pwd        压缩密码
     */
    public static File createZip(String inputDir, String outputFile, String pwd) {
        try {
            ZipFile zipFile;
            ZipParameters zipParameters = new ZipParameters();
            if (StrUtil.isNotBlank(pwd)) {
                zipFile = new ZipFile(outputFile, pwd.toCharArray());
                zipParameters.setEncryptFiles(true);
                zipParameters.setEncryptionMethod(EncryptionMethod.AES);
                zipParameters.setAesKeyStrength(AesKeyStrength.KEY_STRENGTH_256);
            } else {
                zipFile = new ZipFile(outputFile, pwd.toCharArray());
            }
            File currentFile = new File(inputDir);
            if (!currentFile.isDirectory()) {
                return null;
            }
            File[] files = currentFile.listFiles();
            if (ArrayUtil.isEmpty(files)) {
                return null;
            }
            // 遍历test文件夹下所有的文件、文件夹
            for (File f : files) {
                if (f.isDirectory()) {
                    zipFile.addFolder(f, zipParameters);
                } else {
                    zipFile.addFile(f, zipParameters);
                }
            }
            return zipFile.getFile();
        } catch (Exception e) {
            e.printStackTrace();
        }
        return null;
    }

    public static void main(String[] args) {
        List<String> list = new ArrayList<>();
        list.add("D:\\email.html");
        list.add("D:\\email2.html");
        createZip(list, "D:\\MPU日志.zip", "kfd888");
        System.out.println("压缩完成");
    }

}
